package com.jack.xiaoer.util;


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Jackaroo Zhang on 2018/11/9.
 */
public class JWTUtil {

    // Token密钥
    private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";

    // Token过期时间：7天
    private static final int calendarField = Calendar.DATE;

    private static final int calendarInterval = 7;

    private static ObjectMapper objectMapper = new ObjectMapper();


    /*
    iss: jwt签发者

    sub: jwt所面向的用户

    aud: 接收jwt的一方

    exp: jwt的过期时间，这个过期时间必须要大于签发时间

    nbf: 定义在什么时间之前，该jwt都是不可用的.

    iat: jwt的签发时间

    jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。
    */

    /**
     * 生成Token
     * @param payload
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public static <T> String getToken(T payload) {
        Date iatDate = new Date();

        Calendar nowTime = Calendar.getInstance();
        nowTime.add(calendarField, calendarInterval);
        Date expireDate = nowTime.getTime();

        Map<String, Object> headerClaims = new HashMap<>();
        headerClaims.put("alg", "HS256");
        headerClaims.put("typ", "JWT");

        String userPayload = null;
        try {
            userPayload = objectMapper.writeValueAsString(payload);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return "";
        }

        String token = JWT.create().withHeader(headerClaims) // header
                .withClaim("user", userPayload) // payload
                .withClaim("iss", "service")
                .withClaim("aud", "web")
                .withIssuedAt(iatDate)
                .withExpiresAt(expireDate)
                .sign(Algorithm.HMAC256(SECRET)); // signature

        return token;
    }

    public static <T> T verifyToken(String token, Class<T> clazz) throws Exception {
        DecodedJWT jwt = null;

        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        jwt = verifier.verify(token);
        Claim user = jwt.getClaim("user");

        String userJson = user.asString();
        if (userJson == null || userJson.trim().length() == 0)
            throw new InvalidClaimException("token valid failly");

        return objectMapper.readValue(userJson, clazz);
    }



}
